/* ============================================================
 * Part of 'Autostop' project
 * Under GPL license - http://www.gnu.org/licenses/gpl.html
 * (c) 2006 - Autostop team
 */

///\file autostop.c Main file for 'autostop' application.

#include <stdlib.h>
#include <stdio.h>
#include <assert.h>			// uses assert()

#include <sqlite3.h>

#include "analyzer.h"
#include "camera.h"

#include "diagnostic.h"

// constants
#define EVENTSDB_FILENAME	"events.sqlite3"		///< file name for events db
#define CONFIGDB_FILENAME	"config.sqlite3"		///< file name for config db
#define DBPATH_ENV			"AUTOSTOP_DBPATH"		///< environment variable for
#define DBPATH_DEFAULT		"/autostop/data"		///< default DB path

// ======================================================
/// Initializes sql
///\return sqlite db handler, or NULL on error
sqlite3* init_sql()
{
	const char* dbpath = NULL;
	char filename[ 1024 ];
	int result = 0;
	sqlite3* p_connection = NULL;

	// get db path
	dbpath = getenv( DBPATH_ENV );
	if ( ! dbpath )
	{
		// fallback to default, hard-coded path
		dbpath = DBPATH_DEFAULT;
	}

	// create filename
	snprintf( filename, 1024 - 1, "%s/%s", dbpath, EVENTSDB_FILENAME );

	// try open sqlite
	result = sqlite3_open( filename, & p_connection );
	if ( result == SQLITE_OK )
	{
		// SUCCESS
		message("dbfile '%s' open sucessfully\n", filename );
		return p_connection;
	}
	else if ( p_connection )
	{
		// get error message
		const char* msg = sqlite3_errmsg( p_connection );
		error("sqlite error when opening '%s': %s\n", filename, msg );
		sqlite3_close( p_connection );
		p_connection = NULL;
	}
	else
	{
		error("error opening sqlite3 connection\n");
	}

	return NULL;
}

// ======================================================
/// Initializes analyzer process
///\return process handler, or NULL on error
pprocess_t init_process()
{
	pprocess_t p_process = NULL;

	// create process
	p_process = create_process();

	if ( ! p_process )
	{
		error("Error createing process\n");
	}

	// TODO load markers, load configuration

	return p_process;
}
// ======================================================
/// Main entry point
void report_object( pobject_t p_object, sqlite3* p_sql )
{
	assert( p_object );
	assert( p_sql );
	// TODO report
	message("object reported");
}

// ======================================================
/// Main entry point
int main( int argc, char** argv )
{
	// we need 3 things here: sqlite, camera driver and analyzer
	// (AKA the good, the bad and the ugly)
	sqlite3*	p_sql		= NULL;
	pprocess_t	p_process	= NULL;
	pimage_t	p_image		= NULL;
	int 		bufferSize	= 0;
	double		max_speed	= 10.0;		// max allowed speed, [m/s] TODO read from config
	
	// init camera device
	message("Initializing camera...\n");
	if ( CAMERA_ERROR == camera_init() )
	{
		error("Error initilizing camera: %s\n", camera_error_message() );
	}
	
	// init sqlite connection
	message("Initializing sql connection...\n");
	p_sql = init_sql();

	if ( ! p_sql ) {
		error("Error initializing sql, aborintg\n");
		return 1;
	}
	
	// init analyzer process
	p_process = init_process();
	if ( ! p_process ) {
		error("Error initializing process\n");
		return 2;
	}
	// allocate image data buffer
	p_image		= create_image( camera_image_width(), camera_image_height() );
	bufferSize	= camera_image_width() * camera_image_height();
	if ( ! p_image )
	{
		error("Error allocating frame buffer\n");
		return 2;
	}

	
	//  Main loop - one iteration per frame
	while ( 1 )
	{
		int cameraResult	= CAMERA_OK;	// result returned by camera routines
		uint64_t timestamp	= 0;			// frame timestamp
		
		//  Obtain image from driver
		cameraResult = camera_get_image( p_image->pixels, bufferSize, &timestamp );
		if ( CAMERA_OK != cameraResult )
		{
			error("Error obtaining image from camera, aborting: %s\n",
				camera_error_message()
				);
			return 2;
		}

		// Add image to process
		add_frame( p_process, p_image, timestamp );

		// Search process output for interesting moving object

		int object	= 0;			// object loop counter
		for( object = 0; object < p_process->object_number; object ++ )
		{
			object_t* p_object = p_process->objects + object;
			// if object has interesting speed, report it and remove from process
			// TODO remove only old objects
			if ( p_object->speed > max_speed )
			{
				report_object( p_object, p_sql );
				remove_object( p_process, object );
				break; // one object per frame is enough for now
				// if notm we will have to deal with issues with changing indexes
			}
			
		} // object loop

	} // main loop

	// basically... that's all, folks!

	return 0;
}

// eof

